package org.sction.core;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.Hashtable;

import org.apache.log4j.Logger;

/**
 * @author 作者 : sorc
 * @version 创建时间：2012-3-15 下午12:27:59
 * 
 *          类说明
 */
public class ClassLoader extends java.lang.ClassLoader {
	Hashtable<String, Class<?>> loadedClasses;
	private static final Logger logger = Logger.getLogger(ClassLoader.class);

	public ClassLoader() {
		loadedClasses = new Hashtable<String, Class<?>>();
	}

	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		return super.findClass(name);
	}

	@Override
	protected synchronized Class<?> loadClass(String name, boolean resolve)
			throws ClassNotFoundException {
		Class<?> newClass;
		byte[] classData;

		newClass = (Class<?>) loadedClasses.get(name);
		// 如果类数据已经存在且resolve值为true，则解析它。
		if (newClass != null) {
			if (resolve)
				resolveClass(newClass);
			return newClass;
		}
		try {
			newClass = findSystemClass(name);
			return newClass;
		} catch (ClassNotFoundException e) {
			logger.error(name + " ClassNotFound!", e);
		}
		try {
			// 用自定义方法载入类数据，存放于字节数组classData中。
			classData = getClassData(name);
			// 由字节数组所包含的数据建立一个class类型的对象。
			newClass = defineClass(null, classData, 0, classData.length);
			if (newClass == null) {
				logger.error(name + " ClassNotFound!");
				throw new ClassNotFoundException(name);
			}
		} catch (Exception e) {
			logger.error(name + " is not a system class!", e);
			throw new ClassNotFoundException(name);
		}
		loadedClasses.put(name, newClass);
		// 如果resolve值为true，则解析类数据。
		if (resolve) {
			resolveClass(newClass);
		}
		return newClass;

	}

	protected byte[] getClassData(String className) throws IOException {
		byte[] data;
		int length;
		try {
			// 从网络中采用URL类的方法 载入指定URL地址的类的数据。
			URL url = new URL(className.endsWith(".class") ? className
					: className + ".class");
			URLConnection connection = url.openConnection();
			InputStream inputStream = connection.getInputStream();
			length = connection.getContentLength();
			data = new byte[length];
			inputStream.read(data);
			inputStream.close();
			return data;
		} catch (Exception e) {
			logger.error(className + " IOException!", e);
			throw new IOException(className);
		}
	}

}
